#include "QLibSsh/SshShellConnection.h"

#include "QLibSsh/sshsession.h"

namespace {
    constexpr uint M_SECOND = 100000;
}

SshShellConnection::SshShellConnection(SshLoginKeys loginKeys, QObject* parent)
    : QObject(parent)
    , mLoginKeys(std::move(loginKeys))
{
}

SshShellConnection::~SshShellConnection()
{
}


void SshShellConnection::ConnectSsh()
{
    auto sshSession = SshSession(mLoginKeys.user, mLoginKeys.host, mLoginKeys.port, mLoginKeys.password);

    if (!sshSession.IsNull() && !sshSession.connect()) {
        emit SshStandardError(sshSession.GetError());
        emit SshDisconnected();
        return;
    }

    auto sshChannel = SshChannel(sshSession.CreateChannel());
    if (sshChannel.IsNull()) {
        emit SshStandardError(sshSession.GetError());
        emit SshDisconnected();
        return;
    }

    if (!sshChannel.IsOpen() && !sshChannel.Open()) {
        emit SshStandardError(sshSession.GetError());
        emit SshDisconnected();
        return;
    }

    if (!sshChannel.RunInteractiveShell()) {
        emit SshStandardError(sshSession.GetError());
        emit SshDisconnected();
        return;
    }

    QByteArray buffer;
    buffer.resize(1024);
    int length = 0;
    while ((length = sshChannel.Read(buffer.data(), buffer.size(), 200)) > 0) {
        buffer.resize(length);
        emit SshStandardOutput(buffer.toStdString());
        buffer.resize(1024);
    }
    if (length == SSH_ERROR) {
        emit SshStandardError(sshSession.GetError());
        emit SshDisconnected();
        return;
    }

    emit SshConnected();
    {
        std::scoped_lock lock(mMutex);
        mIsConnect = true;
    }
    while (sshChannel.IsOpen() && mIsConnect) {
        auto command = const_cast<char*>(mCommand.c_str());
        if (!mCommand.empty() && sshChannel.Write(command, strlen(command))) {
            mIsExecing = true;
            emit SshExecStarted();
            mCommand.clear();
        }
        QByteArray buffer;
        buffer.resize(1024);
        int length = 0;
        while (mIsExecing && (length = sshChannel.Read(buffer.data(), buffer.size(), 200)) > 0) {
            buffer.resize(length);
            emit SshStandardOutput(buffer.toStdString());
            buffer.resize(1024);
        }
        if (length == SSH_ERROR) {
            emit SshStandardError(sshSession.GetError());
            emit SshDisconnected();
            break;
        }
        if (mIsExecing) {
            emit SshExecFinished();
            mIsExecing = false;
        }
        usleep(M_SECOND); // 避免高 CPU 使用率
    }
    emit SshDisconnected();
}

void SshShellConnection::DisconnectSsh()
{
    std::scoped_lock lock(mMutex);
    mIsConnect = false;
}

void SshShellConnection::SendCommand(const std::string& command)
{
    mCommand = command;
    qDebug() << mCommand;
}
